package games.graphPath;

import games.graphPath.Graph.Edge;
import games.graphPath.Graph.Vertex;
import games.graphPath.GraphPathGenticSearch.GeneticVertex;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.ArrayList;

/**
 * This class represents the result of some search algorithm running on some game. 
 * Fill in what ever you think should be here. 
 */
public class GraphPathResult {

	public final static int A_STAR = 0;
	public final static int GENETIC = 1;
	public final static int GRADIANT = 2;	

	private BufferedWriter _bw;
	
	private ArrayList<Result> _results;

	private class Result
	{
		public Result(int type)
		{
			_type = type;
			_path = null;
		}

		public Result(int type, ArrayList<Vertex> path,
				ArrayList<Integer> moveCosts,
				int cost, int depth, long time, long buildTime)
		{
			_type = type;
			_path = path;
			_moveCosts = moveCosts;
			_cost = cost;
			_depth = depth;
			_time = time;
			_buildTime = buildTime;
		}

		private int _type;
		private ArrayList<Vertex> _path;
		private ArrayList<Integer> _moveCosts;
		private int _cost;
		private int _depth;
		private long _time;
		private long _buildTime;

	}

	public GraphPathResult()
	{
		_results = new ArrayList<Result>();		
	}

	/*
	public GraphPathResult(ArrayList<GraphPathAStarState> path, int depth, long time) {
		_depth = depth;
		_time = time;
		_cost = 0;
		_moveCosts = new int[path.size()];
		for (int i=0; i<path.size(); i++)
		{
			GraphPathAStarState s = path.get(i);
			_moveCosts[i] = s.getMoveCost();
			_cost += _moveCosts[i];			
			_path.add(s.getCur());
		}
	}
	 */


	public void addFailed(int type) {
		_results.add(new Result(type));
	}

	//add AStar result
	public void add(int type, GraphPathAStarState finalState, int depth,long totalTime) {
		ArrayList<Vertex> path = new ArrayList<Vertex>();
		ArrayList<Integer>moveCosts = new ArrayList<Integer>();
		for (GraphPathAStarState s = finalState; s!=null; s=s.getParent())
		{
			path.add(s.getCur());
			moveCosts.add(s.getMoveCost());
		}
		_results.add(new Result(type, path, moveCosts, finalState.getCost(), depth,totalTime,-1));
	}

	//add genetic result
	public void add(int type, ArrayList<GeneticVertex> arrayList, long time, long buildTime) {
		ArrayList<Vertex> path= new ArrayList<Vertex>();
		ArrayList<Integer> moveCosts = new ArrayList<Integer>();
		int cost = 0;
		//ignore cost of first vertex
		path.add(arrayList.get(0).getVertex());

		for (int i=0; i<arrayList.size(); i++)
		{
			path.add(arrayList.get(i).getVertex());
			moveCosts.add(arrayList.get(i).weight());
			cost += arrayList.get(i).weight();
		}
		_results.add(new Result(type, path, moveCosts, cost,-1 , time, buildTime));
	}
	
	//add gradient result
	public void add(int type, ArrayList<Edge> bestPath, int cost, long time) {
		ArrayList<Vertex> path= new ArrayList<Vertex>();
		ArrayList<Integer> moveCosts = new ArrayList<Integer>();
		for (Edge edge : bestPath)
		{
			path.add(edge.getSrc());
			moveCosts.add(edge.getCost());
		}
		path.add(bestPath.get(bestPath.size()-1).getDst());
		
		_results.add(new Result(type, path, moveCosts,cost,-1,time,-1));
		
		
	}

	public void printResults(String outputName) throws IOException{
		
		File output = new File(outputName);
		_bw = new BufferedWriter(new OutputStreamWriter (new FileOutputStream(output))); 
		
		for (int i=0; i<_results.size(); i++)
		{
			Result r = _results.get(i);
			println();
			String algo = "";
			switch (r._type)
			{
			case A_STAR:
				printAStar(r,i);
				break;
			case GENETIC:
			case GRADIANT:
				printG(r,i);
				break;
			
			}
		}
		_bw.close();
	}

	private void print(String str) throws IOException
	{
		if (_bw!=null)
			_bw.write(str);
		else
			System.out.print(str);
	}
	
	private void println(String str) throws IOException
	{
		if (_bw!=null)
		{
			_bw.write(str);
			_bw.newLine();
		}
		else
			System.out.println(str);
	}
	
	private void println() throws IOException{
		if (_bw!=null)
		{
			_bw.newLine();
		}
		else
			System.out.println();
	}
	
	private void printAStar(Result r, int i) throws IOException
	{
		if (r._path==null)
		{
			println("Test #" + i + ", Running with AStar FAILED");
			return;
		}
		println("Test #" + i + ", Running with AStar");
		for (int j=r._path.size()-1; j>=0; j--)
		{
			print(r._path.get(j).getIndex()+"\t");
			//if (i % 10 == 0)
			//println();
		}
		println();
		print("TOTAL COST: " + r._cost);
		print("\tDEPTH: "+ r._depth);
		println("\tTIME: " + r._time);
	}
	
	private void printG(Result r, int i) throws IOException
	{
		String type = r._type==GENETIC? "Genetic" : "Gradiant";
		if (r._path==null)
		{
			println("Test #" + i + ", Running with "+type+" FAILED");
			return;
		}
		println("Test #" + i + ", Running with "+type);
		for (int j=0; j<r._path.size(); j++)
		{
			print(r._path.get(j).getIndex()+"\t");
			//if (i % 10 == 0)
			//println();
		}
		println();
		print("TOTAL COST: " + r._cost);
		if (r._type==GENETIC)
				print("\tBUILD TIME: "+ r._buildTime);
		println("\tTIME: " + r._time);

	}
	
	
}
